﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Configuration;
using TpSettings;

namespace Persistency.DataAccess
{
	/// <summary>
	/// Kapselt die Erstellung und Protokollierung von Ausnahmen.
	/// </summary>
	internal static class ExceptionBuilder
	{
		/// <summary>
		/// Protokolliert die Ausnahme <paramref name="ex"/>.
		/// </summary>
		/// <param name="ex">Die zu protokollierende Ausnahme.</param>
		private static void TraceException(Exception ex)
		{
			// Den Parameter validieren. Eine Ausnahme werfen, die direkt hier
			// instanziiert wird, da alles andere in einer Endlosschleife
			// resultieren könnte.
			if (ex == null)
			{
				Exception exception = new ArgumentNullException("ex");
				Trace.TraceError(exception.ToString());
				throw exception;
			}

			// Die StackTrace Eigenschaft einer Ausnahme wird gefüllt, sobald
			// die Ausnahme geworfen wird. Es wird eine leere Zeichenfolge
			// zurückgegeben, wenn die Ausnahme noch nicht geworfen wurde.
			// Deshalb muss an dieser Stelle der aktuelle StackTrace
			// mitprotokolliert werden, um den Fehler später beheben zu können.
			StackTrace st = new StackTrace();
			string trace = ex.ToString();
			trace += st.ToString();

			// Die Ausnahme als Fehler protokollieren.
			Trace.TraceError(trace);
		}

		/// <summary>
		/// Erstellt und protokolliert eine Ausnahme mit einer bestimmten
		/// Fehlermeldung im Falle eines Konfigurationsfehlers.
		/// </summary>
		/// <param name="message">Eine Fehlermeldung die beschreibt, warum diese
		/// Ausnahme geworfen wurde.</param>
		/// <returns>Eine Ausnahme, die geworfen werden soll.</returns>
		public static Exception ConfigurationErrorsException(string message)
		{
			// Eine ConfigurationErrorsException als innere Ausnahme bauen
			// und einen SqlError mit ihr zurückgeben.
			Exception ex = new ConfigurationErrorsException(message);
			TraceException(ex);
			return ex;
		}

		/// <summary>
		/// Erstellt und protokolliert eine Ausnahme, wenn ein Methodenargument
		/// <see langword="null" /> war.
		/// </summary>
		/// <param name="paramName">Der Name des Parameters, der die Ausnahme
		/// ausgelöst hat.</param>
		/// <returns>Eine Ausnahme, die geworfen werden soll.</returns>
		public static Exception ArgumentNullException(string paramName)
		{
			// Eine ArgumentNullException bauen, diese protokollieren und
			// zurückgeben.
			Exception ex = new ArgumentNullException(paramName);
			TraceException(ex);
			return ex;
		}

		/// <summary>
		/// Erstellt und protokolliert eine Ausnahme, wenn ein Methodenargument
		/// ungültig war.
		/// </summary>
		/// <param name="paramName">Der Name des Parameters, der die Ausnahme
		/// ausgelöst hat.</param>
		/// <param name="message">Eine Fehlermeldung die beschreibt, warum diese
		/// Ausnahme geworfen wurde.</param>
		/// <returns>Eine Ausnahme, die geworfen werden soll.</returns>
		public static Exception ArgumentException(string paramName,
		    string message)
		{
			// Eine ArgumentException bauen, diese protokollieren und
			// zurückgeben.
			Exception ex = new ArgumentException(message, paramName);
			TraceException(ex);
			return ex;
		}

		/// <summary>
		/// Erstellt und protokolliert eine Ausnahme, wenn etwas bei der
		/// Kommunikation mit der Datenbank schief gegangen ist.
		/// </summary>
		/// <param name="innerException">Die Ausnahme, die der Auslöser für
		/// diese Ausnahme ist.</param>
		/// <returns>Eine Ausnahme, die geworfen werden soll.</returns>
		public static Exception SqlError(Exception innerException)
		{
			// Eine DataAccessException bauen, diese protokollieren und
			// zurückgeben.
			Exception ex = new DataAccessException(
			    TpResource.DatabaseExceptionOccurred, innerException);
			TraceException(ex);
			return ex;
		}
	}
}
